/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "StdAfx.h"
#include ".\phantomwindow.h"
#include "WindowFactory.h"

CPhantomWindow::CPhantomWindow(void)
: MyType(0)
, aWnd(SSI_NULL)
{
	if(MyClass == ""){
		MyType = 0;
	}else{
		MyType = Phantom_RegisterWindow(this);
	}
}

CPhantomWindow::CPhantomWindow(String& ClassName)
: MyType(0)
, aWnd(SSI_NULL)
{
	MyClass = ClassName;
	if(MyClass == ""){
		MyType = 0;
	}else{
		MyType = Phantom_RegisterWindow(this);
	}
}


CPhantomWindow::~CPhantomWindow(void)
{
}

CPhantomWindow* CPhantomWindow::MakeWindow(void)
{
	return new CPhantomWindow();
}

int CPhantomWindow::FunctionProcessor(SSI_FunctionAPI& theAPI)
{
	if(theAPI.m_FunctionName == "GetText"){
		CDataString a;
		theAPI.m_ReturnStatus = GetText(a.Data);
		theAPI.SetReturnData(&a);
	}else if(theAPI.m_FunctionName == "SetText"){
		String s = SSI_EXTRACT(CDataString, 0);
		theAPI.m_ReturnStatus = SetText(s);
	}else if(theAPI.m_FunctionName == "Minimize"){
		aWnd->ShowWindow(SW_SHOWMINIMIZED);
	}else if(theAPI.m_FunctionName == "Maximize"){
		aWnd->ShowWindow(SW_SHOWMAXIMIZED);
	}else if(theAPI.m_FunctionName == "Restore"){
		aWnd->ShowWindow(SW_RESTORE);
	}else if(theAPI.m_FunctionName=="Close"){
		aWnd->PostMessage(WM_CLOSE, 0, 0);	// Must be post in case require pre-close commands
	//}else if(theAPI.m_FunctionName == "KeyDown"){
	//	SetActive();
	//	String s = SSI_EXTRACT(CDataString, 0);
	//	theAPI.m_ReturnStatus = TypeKeys2(s, 1);
	//}else if(theAPI.m_FunctionName == "KeyUp"){
	//	SetActive();
	//	String s = SSI_EXTRACT(CDataString, 0);
	//	theAPI.m_ReturnStatus = TypeKeys2(s, 2);
	}else if(theAPI.m_FunctionName == "MoveWin"){
		int inX, inY, inH, inW;
		RECT aRect;

		aWnd->GetWindowRect(&aRect);
    if(aWnd->GetParent()){
			aWnd->GetParent()->ScreenToClient(&aRect);
		}

		inX = SSI_EXTRACT(CDataInt, 0);
		inY = SSI_EXTRACT(CDataInt, 1);
		inH = (aRect.bottom)-(aRect.top);
		inW = (aRect.right)-(aRect.left);
		aWnd->MoveWindow(inX, inY, inW, inH, 1);

	}else if(theAPI.m_FunctionName == "ResizeWin"){
		int inX, inY, inH, inW;
		RECT aRect;

		aWnd->GetWindowRect(&aRect);
		if(aWnd->GetParent()){
			aWnd->GetParent()->ScreenToClient(&aRect);
		}
		inX = aRect.left;
		inY = aRect.top;
		inW = SSI_EXTRACT(CDataInt, 0);
		inH = SSI_EXTRACT(CDataInt, 1);
		aWnd->MoveWindow(inX, inY, inW, inH, 1);

	}else if(theAPI.m_FunctionName == "MouseMove"){
		int X, Y;
		X = SSI_EXTRACT(CDataInt, 0);
		Y = SSI_EXTRACT(CDataInt, 1);
		theAPI.m_ReturnStatus = MouseMove(X, Y);
//	}else if(theAPI.m_FunctionName == "MouseClick"){
//		int X, Y, iType, iButton;
//		iButton = SSI_EXTRACT(CDataInt, 0);
//		X = SSI_EXTRACT(CDataInt, 1);
//		Y = SSI_EXTRACT(CDataInt, 2);
//		iType = SSI_EXTRACT(CDataInt, 3);
//		theAPI.m_ReturnStatus = MouseClick(iButton, X, Y, iType);
//	}else if(theAPI.m_FunctionName == "TypeKeys"){
//		String s;
//		s = SSI_EXTRACT(CDataString, 0);
//		SetActive();
//		theAPI.m_ReturnStatus = TypeKeys(s);  
	}else if((theAPI.m_FunctionName == "BringToTop") || (theAPI.m_FunctionName == "SetActive")){
		theAPI.m_ReturnStatus = SetActive();
	}else if(theAPI.m_FunctionName == "GetWindowX"){
		RECT* lpRect = new RECT;
		lpRect->bottom = 0;
		lpRect->top = 0;
		lpRect->left = 0;
		lpRect->right = 0;

		aWnd->GetWindowRect(lpRect);

		CDataInt ret;
		ret.Data = int(lpRect->left);
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);

		delete lpRect;
	}else if(theAPI.m_FunctionName == "GetWindowY"){
		RECT* lpRect = new RECT;
		lpRect->bottom = 0;
		lpRect->top = 0;
		lpRect->left = 0;
		lpRect->right = 0;

		aWnd->GetWindowRect(lpRect);

		CDataInt ret;
		ret.Data = int(lpRect->top);
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
		delete lpRect;
	}else if(theAPI.m_FunctionName == "GetWindowWidth"){
		RECT* lpRect = new RECT;
		lpRect->bottom = 0;
		lpRect->top = 0;
		lpRect->left = 0;
		lpRect->right = 0;

		aWnd->GetWindowRect(lpRect);

		CDataInt ret;
		ret.Data =  int(lpRect->right - lpRect->left);
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);

		delete lpRect;
	}else if(theAPI.m_FunctionName == "GetWindowHeight"){
		RECT* lpRect = new RECT;
		lpRect->bottom = 0;
		lpRect->top = 0;
		lpRect->left = 0;
		lpRect->right = 0;

		aWnd->GetWindowRect(lpRect);

		CDataInt ret;
		ret.Data =  int(lpRect->bottom - lpRect->top);
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);

		delete lpRect;
	}else if(theAPI.m_FunctionName == "IsActive"){
		CDataInt ret;
		ret.Data = 0;
		CWnd* aWin = aWnd->GetTopLevelParent();
		HWND Active;		
		Active = GetForegroundWindow();
		if(Active && aWin){
			if(Active == aWin->m_hWnd){
				ret.Data = 1;
			}
		}
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
	}else if(theAPI.m_FunctionName == "Blink"){
		int Count;
		Count = SSI_EXTRACT(CDataInt, 0);
		Blink(Count);
	}else if(theAPI.m_FunctionName == "GetCaretX"){
		CPoint p = aWnd->GetCaretPos();
		CDataInt ret;
		ret.Data = int(p.x);
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
	}else if(theAPI.m_FunctionName == "GetCaretY"){
		CPoint p = aWnd->GetCaretPos();
		CDataInt ret;
		ret.Data = int(p.y);
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
	}else{
		theAPI.m_ReturnStatus.Format(sERROR, "Function '%s' not supported by window class '%s'", theAPI.m_FunctionName.Str(), MyClass.Str());
	}

	return 1;
}

int CPhantomWindow::InitWindow(void)
{
	return 1;
}

String CPhantomWindow::GetClass(void)
{
	return MyClass;
}

CStatus CPhantomWindow::GetText(String& RetText)
{
	char Params[SHRT_MAX];  //Because needs to know the size, for some reason
	aWnd->SendMessage(WM_GETTEXT, SHRT_MAX, (LPARAM)&Params);
	RetText.Format("%s", &Params[0]);
	return STAT_OK;
}

int CPhantomWindow::Attach(HWND InWnd)
{
	aWnd = new CWnd;
	MyWin = InWnd;
	return aWnd->Attach(InWnd);

}

int CPhantomWindow::Detach(void)
{
	MyWin = 0;
	if(aWnd){
		aWnd->Detach();
		delete aWnd;
		aWnd = 0;
	}
	return 1;
}

int CPhantomWindow::SetClass(String& NewClass)
{
	MyClass = NewClass;
	return 1;
}

CStatus CPhantomWindow::SetText(String& NewText)
{
	aWnd->SendMessage(WM_SETTEXT, 0, (LPARAM)NewText.Str());
	return STAT_OK;
}

CStatus CPhantomWindow::MouseMove(int X, int Y)
{
	POINT Pt;

	Pt.x = X;
	Pt.y = Y;
	
	LPARAM lParam;
	int iy = Pt.y << 16;
	lParam = LPARAM(Pt.x | iy);

	aWnd->ClientToScreen(&Pt);
	
	if(!SetCursorPos(Pt.x, Pt.y))
	{
		//Error.Format(ERR00350, (LPCTSTR)Params);
		//LogError(Error);
		//return FALSE;
		MAKEERR0(ERR_P01610);
	}
	if(!aWnd->PostMessage(WM_MOUSEMOVE, 0, lParam)){
		MAKEERR0(ERR_P01611);
	}
	return STAT_OK;
}

CStatus CPhantomWindow::SetActive(void)
{
	CWnd* TopWin = aWnd->GetTopLevelOwner();
	if(TopWin == SSI_NULL){
		TopWin = aWnd;
	}
	HWND hWnd = TopWin->m_hWnd;
	HWND Fore = GetForegroundWindow();
	if(GetWindowThreadProcessId(hWnd, SSI_NULL) != GetWindowThreadProcessId(Fore, SSI_NULL)){
		SetForegroundWindow(hWnd);
		BringWindowToTop(hWnd);
		SetActiveWindow(hWnd);
		SetFocus(hWnd);			
	}
	return STAT_OK;
}


void CPhantomWindow::Blink(int iCount)
{
	int ctr = 0;
	DWORD OldStyleEx = aWnd->GetExStyle();
	DWORD OldStyle = aWnd->GetStyle();

	DWORD BlinkEx = WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE;
	OldStyleEx = OldStyleEx & (BlinkEx | WS_EX_DLGMODALFRAME);
 
  DWORD Blink = WS_BORDER | WS_DLGFRAME | WS_THICKFRAME;
	OldStyle = OldStyle & (Blink);

  int OldState = SW_HIDE;
	if(aWnd->IsWindowVisible()){
		OldState = SW_SHOW;
	}

	while(ctr < iCount){
		//aWnd->ModifyStyle(OldStyle, Blink, 0);
		//aWnd->ModifyStyleEx(OldStyleEx, BlinkEx, 0);
		//aWnd->RedrawWindow();
		aWnd->ShowWindow(SW_HIDE);
    Sleep(250);
		aWnd->ShowWindow(SW_SHOW);
		aWnd->RedrawWindow();
		//aWnd->ModifyStyle(Blink, OldStyle, 0);
    //aWnd->ModifyStyleEx(BlinkEx, OldStyleEx, 0);
		//aWnd->RedrawWindow();
		Sleep(250);
		ctr++;
	}
	aWnd->ShowWindow(OldState);
}

void CPhantomWindow::SetExtraData(String& in_ExtraData)
{
	ExtraData = in_ExtraData;
}
